#!/bin/bash
# #######################################################################################
#
# Copyright (c) KylinSoft Co., Ltd. 2024. All rights reserved.
# SecureGuardian is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#     http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Description: Security Baseline Check Script for 1.1.20
#
# #######################################################################################
#!/bin/bash

# 功能说明:
# 本脚本用于修复用户和系统配置文件中不正确设置的 PATH 变量，确保系统安全，防止系统命令被恶意替代。

# 修复系统级配置中的不安全 PATH 设置
fix_system_path() {
    echo "修复系统级配置中的不安全 PATH 设置..."
    local system_files=("/etc/profile" $(find /etc/profile.d/ -type f))

    for file in "${system_files[@]}"; do
        if [ -f "$file" ] && grep -q "export PATH=" "$file"; then
            local new_path=""
            local modified=0
            while IFS= read -r line; do
                if [[ "$line" =~ export\ PATH=.* ]]; then
                    local paths=$(echo "$line" | sed 's/.*export PATH="\?\([^"]*\)"\?.*/\1/' | tr ':' '\n')
                    local safe_paths=""
                    local unsafe_paths=""

                    while IFS= read -r path; do
                        if [[ "$path" =~ ^(\.|\.\.|\./|\.\./) ]]; then
                            unsafe_paths="$unsafe_paths$path:"
                            modified=1
                        else
                            safe_paths="$safe_paths$path:"
                        fi
                    done <<< "$paths"

                    safe_paths=$(echo "$safe_paths" | sed 's/:$//')
                    unsafe_paths=$(echo "$unsafe_paths" | sed 's/:$//')

                    if [[ -n "$unsafe_paths" ]]; then
                        new_path="$new_path# $line\nexport PATH=\"$safe_paths\"\n"
                    else
                        new_path="$new_path$line\n"
                    fi
                else
                    new_path="$new_path$line\n"
                fi
            done < "$file"

            if [[ $modified -eq 1 ]]; then
                # 备份原文件
                cp "$file" "${file}.bak"
                echo -e "$new_path" > "$file"
                echo "$file 中的不安全 PATH 设置已修复并备份为 ${file}.bak。"
            else
                echo "$file 中的 PATH 设置没有问题。"
            fi
        fi
    done
}

# 修复用户配置文件中的不安全 PATH 设置
fix_user_path() {
    local file=$1

    if [ -f "$file" ] && grep -q "export PATH=" "$file"; then
        local new_path=""
        local modified=0
        while IFS= read -r line; do
            if [[ "$line" =~ export\ PATH=.* ]]; then
                local paths=$(echo "$line" | sed 's/.*export PATH="\?\([^"]*\)"\?.*/\1/' | tr ':' '\n')
                local safe_paths=""
                local unsafe_paths=""

                while IFS= read -r path; do
                    if [[ "$path" =~ ^(\.|\.\.|\./|\.\./) ]]; then
                        unsafe_paths="$unsafe_paths$path:"
                        modified=1
                    else
                        safe_paths="$safe_paths$path:"
                    fi
                done <<< "$paths"

                safe_paths=$(echo "$safe_paths" | sed 's/:$//')
                unsafe_paths=$(echo "$unsafe_paths" | sed 's/:$//')

                if [[ -n "$unsafe_paths" ]]; then
                    new_path="$new_path# $line\nexport PATH=\"$safe_paths\"\n"
                else
                    new_path="$new_path$line\n"
                fi
            else
                new_path="$new_path$line\n"
            fi
        done < "$file"

        if [[ $modified -eq 1 ]]; then
            # 备份原文件
            cp "$file" "${file}.bak"
            echo -e "$new_path" > "$file"
            echo "$file 中的不安全 PATH 设置已修复并备份为 ${file}.bak。"
        else
            echo "$file 中的 PATH 设置没有问题。"
        fi
    fi
}

# 修复所有用户的 .bashrc 和 .bash_profile 中的不安全 PATH 设置
fix_users_path() {
    echo "修复所有用户配置中的不安全 PATH 设置..."
    while IFS=: read -r username _ _ _ _ homedir shell; do
        # 跳过 nologin 用户
        if [[ "$shell" == */nologin ]]; then
            continue
        fi

        # 忽略不存在的家目录
        if [ ! -d "$homedir" ]; then
            continue
        fi

        # 修复用户家目录下的配置文件
        for file in "$homedir/.bashrc" "$homedir/.bash_profile"; do
            fix_user_path "$file"
        done
    done < /etc/passwd
}

# 自测部分
self_test() {
    local test_user="testuser"
    local test_homedir="/home/$test_user"
    local test_bashrc="$test_homedir/.bashrc"
    local test_bash_profile="$test_homedir/.bash_profile"

    echo "自测: 创建测试用户和配置文件"

    # 创建测试用户和家目录
    useradd -m "$test_user"
    if [ $? -ne 0 ]; then
        echo "自测失败: 无法创建测试用户。"
        return 1
    fi
    echo 'export PATH="$PATH:/usr/local/bin:."' > "$test_bashrc"
    echo 'export PATH="$PATH:/usr/local/bin:."' > "$test_bash_profile"

    # 检查修复前的设置
    if grep -E "export PATH=.*(\.|\.\.|\./|\.\./).*" "$test_bashrc" || grep -E "export PATH=.*(\.|\.\.|\./|\.\./).*" "$test_bash_profile"; then
        echo "自测前: 检测到测试用户配置文件中的不安全 PATH 设置。"
    else
        echo "自测失败: 未检测到测试用户配置文件中的不安全 PATH 设置。"
        userdel -r "$test_user"
        return 1
    fi

    # 修复测试用户的配置
    fix_user_path "$test_bashrc"
    fix_user_path "$test_bash_profile"

    # 检查修复后的设置
    if grep -E "^export PATH=.*(\.|\.\.|\./|\.\./).*" "$test_bashrc" || grep -E "^export PATH=.*(\.|\.\.|\./|\.\./).*" "$test_bash_profile"; then
        echo "自测失败: 测试用户配置文件中的不安全 PATH 设置未修复。"
        userdel -r "$test_user"
        return 1
    else
        echo "自测成功: 测试用户配置文件中的不安全 PATH 设置已修复。"
        userdel -r "$test_user"
        return 0
    fi
}

# 使用说明
show_usage() {
    echo "用法: $0 [--self-test]"
    echo "选项:"
    echo "  --self-test                进行自测"
    echo "  /?                         显示此帮助信息"
}

# 检查命令行参数
if [[ "$1" == "--self-test" ]]; then
    self_test
    exit $?
elif [[ "$1" == "/?" ]]; then
    show_usage
    exit 0
else
    # 执行修复
    fix_system_path
    fix_users_path
    echo "PATH 环境变量设置已修复。"
    exit 0
fi

